package Obstacle;

import squarePackage.Square;
import be.kuleuven.cs.som.annotate.Basic;
import be.kuleuven.cs.som.annotate.Raw;

public class Wall {
	/**
	 * A variable to register the door in a wall
	 */
	private Door door;
	/**
	 * A variable to store  whether or not a wall is slippery 
	 */
	private final boolean isSlippery;
	/**
	 * A variable to store whether or not a wall is terminated
	 */
	private boolean isTerminated;
	/**
	 * A variable to store the first square where the wall is put
	 */
	private Square square1;
	/**
	 * A variable to store the second square where the wall is put
	 */
	private Square square2;
	
	/**
     * A constructor to initialize a wall
     * 
     * @post ...
     * 		|new.hasDoor() == false
     * @post ...
     * 		|new.isSlippery() == false
     * @post ...
     *		|new.getSquare() == null
     *@post ...
     *		|new.isTerminated() == false
     * 
     */
	public Wall(){
		door = null;
		isSlippery =  false;
		isTerminated = false;
	}
	
	/**
     * A constructor to initialize a wall
     * 
     * @param door
     * 			the door you wish to set in the wall
     * @post ...
     * 		|new.hasDoor() == true && new.getDoor() == door
     * @post ...
     * 		|new.isSlippery() == false
     * @post ...
     *		|new.getSquare() == null
     *@post ...
     *		|new.isTerminated() == false
     * 
     */
	public Wall(Door door){
		setDoor(door);
		if (this.hasDoor() == false)
			terminate();
		else isTerminated =  false;
		this.isSlippery = false;
	}
	
	/**
     * A constructor to initialize a wall
     * 
     * @post ...
     * 		|new.hasDoor() == false
     * @post ...
     * 		|new.isSlippery() == true
     * @post ...
     *		|new.getSquare() == null
     *@post ...
     *		|new.isTerminated() == false
     * 
     */
	public Wall(boolean isSlippery){
		door = null;
		this.isSlippery = isSlippery;
		this.isTerminated = false;
	}
	
	/**
	 * A method to set a door in a wall
	 * 
	 * @param door
	 * 			the door you wish to set in this wall
	 * @post ...
	 * 		|if (isValidDoor(door))
	 * 		|then new.getDoor() == door && new.getDoor().getWall() == this
	 * 
	 */
	public void setDoor(Door door){
		if (isValidDoor(door)){
			door.setWall(this);
			this.door = door;
			
		}
	}
	
	/**
	 * A method to check whether or not this wall has a door
	 * 
	 * @return true if this wall already has a door
	 */
	public boolean hasDoor(){
		if (door == null)
			return false;
		return true;
	}
	
	/**
	 * A method to get the door of this wall
	 * 
	 * @return the door of this wall
	 */
	@Basic
	public Door getDoor(){
		return door;
	}
	
	/**
	 * A method to check whether or not this door is valid for this wall
	 * 
	 * @param door
	 * 			the door you wish to check
	 * @return true if this door is valid for this wall (the wall hasn't got a door
	 * 			and the door hasn't got a wall)
	 * @return false if this wall is Slippery
	 * @return false if this wall or door is terminated
	 */
	public boolean isValidDoor(Door door) {
		if (this.isSlippery)
			return false;
		else if(!isTerminated() && !door.isTerminated())
			if (hasDoor() == false && door.hasWall() == false)
				return true;
		return false;
	}
	
	
	
	/**
	 * A method to return whether or not this wall is terminated
	 * 
	 * @return true if this wall is terminated
	 */
	@Basic @Raw
	public boolean isTerminated(){
		return isTerminated;
	}
	
	/**
	 * A method to terminate this wall
	 * 
	 * @post ...
	 * 		| new.isTerminated() == true
	 * @post ...
	 * 		|if (this.hasDoor())
	 * 		|then this.getDoor().isTerminated() == true
	 * @post ...
	 * 		|this.getSquare() == null
	 */
	@Raw
	public void terminate(){
		if(hasDoor())
			door.terminate();
		square1 = null;
		square2 = null;
		isTerminated = true;
	}

	/**
	 * A method to remove a door
	 * 
	 * @post ...
	 * 		|this.getDoor().isTerminated == true
	 * @post ...
	 * 		|new.hasDoor() == false
	 *	
	 */
	public void removeDoor(){
		door.terminate();
	}

	/**
	 * A method to set the door at null
	 * 
	 * @post ...
	 * 		|if (this.getDoor().isTerminated())
	 * 		|then new.hasDoor() == false
	 */
	void setDoorNull(){
		if (getDoor().isTerminated())
			door = null;
	}
	
	/**
	 * A method to check whether or not a wall is slippery
	 * 
	 * @return true if the wall is slippery
	 */
	public boolean isSlippery() {
		return isSlippery;
	}

	@Basic@Raw
	/**
	 * A method to set the square(s) for a wall
	 * 
	 * @pre if square1 is not null square2 has to be a neighbour of square1
	 * 
	 * @post ...
	 * 		|if((isValidSquare) && this.getSquare1() == null)
	 * 		|then this.getSquare1() == square
	 * @post ...
	 * 		|if((isValidSquare) && this.getSquare1() != null)
	 * 		|then this.getSquare2() == square
	 * 		
	 * 
	 */
	public void setSquare(@Raw Square square) {
		if (isValidSquare(square) == true){
			if (this.getSquare1() == null){
				square1 = square;
			}
			else{
				square2 = square;
				}
			}
	}
		
	/**
	 * A method to get the first square this wall is set to
	 * 
	 * @return the first square this wall is set to
	 */
	@Basic
	public Square getSquare1(){
		return square1;
	
	}
	
	/**
	 * A method to get the second square this wall is set to
	 * 
	 * @return the second square this wall is set to
	 */
	@Basic
	public Square getSquare2(){
		return square2;
	
	}

	/**
	 * A method to check whether or not a square is valid for a wall to set to
	 * 
	 * @param square
	 * 			the square you wish to set this wall to
	 * @return !(square == null)
	 */
	private boolean isValidSquare(Square square) {
		if (square == null)
			return false;
		return true;
		}

}
